import directives from './directives/directives'
import filters from './filters'

const KEY_RE = /^[^\|]+/;
const COLON_MAP = /([^:]+):([^:]+)/;
const FILTER_RE = /\|[^\|]+/g;
const LOOP_RE = /(\w+)\s+(in)\s+(\w+)/;

function Directive(directiveName, expression) {

    this.key = '';    //双向绑定的key
    this.arg = '';    //例如 v-class="red-box:showRedBox 的 red-box
    this._update = '';    //触发setter时调用的方法
    this.directiveArg = '';    //指令的参数
    this.forPrefix = '';
    this.filters = [];

    const dirToken = directiveName.match(COLON_MAP);

    //获取指令
    let directive = dirToken
        ? directives[dirToken[1]]  //v-on:click 的 on
        : directives[directiveName];//v-for 的 for


    this.directiveArg = dirToken
        ? dirToken[2]   //v-on:click="alert" 的 click,而 v-for 是没有参数的
        : '';

    //v-for="user in users" 的 "user in users"
    const loopToken = expression.match(LOOP_RE);
    //v-class="red-box:showRedBox" 的 "red-box:showRedBox"
    const colonMap = expression.match(COLON_MAP);

    if (loopToken) {
        //如果是v-for
        this.forPrefix = loopToken[1];
        this.key = loopToken[3];
    } else if (colonMap) {
        //如果是v-class="red-box:showRedBox"之类的
        this.key = colonMap[2];
        this.arg = colonMap[1];
    } else {
        //如果是v-text="msg"之类的
        this.key = expression.match(KEY_RE)[0].trim()
    }

    //从指令模板中获取对应的指令
    if (typeof directive == 'function') {
        this._update = directive;
    } else {
        for (let prop in directive) {
            if (prop == 'update') {
                this._update = directive.update;
            } else {
                this[prop] = directive[prop];
            }
        }
    }

    const filtersToken = expression.match(FILTER_RE);
    if (filtersToken) {
        filtersToken.forEach(filterToken => {
            this.filters.push(filters[filterToken.slice(1).trim()]);
        })
    }
}

Directive.prototype.update = function (value) {
    this.filters.forEach(filter => {
        value = filter(value);
    });
    this._update(value);
};

export default Directive;